﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Forms.DataVisualization.Charting;
using System.ComponentModel;
using System.Collections.Specialized;

namespace Xinnos.Lca.Yacht.Analyzer.View
{
    /// <summary>
    /// AssessmentGraphPanel.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class AssessmentGraphPanel : UserControl
    {
        private AssessmentViewModel mViewModel = null;
        private ConfigurationViewModel mConfiguration = null;
        private Chart mChart = null;
        private List<Legend> mLegends = null;
        private string mSeperator = "|";
        public AssessmentGraphPanel()
        {
            InitializeComponent();

            if (null == mViewModel) mViewModel = AssessmentViewModel.GetInstance();
            if (null == mConfiguration) mConfiguration = ConfigurationViewModel.GetInstance();
            if (null == mChart)
            {
                mChart = new Chart();
                formsHost.Child = mChart;
                mChart.ChartAreas.Add(new ChartArea());

                ChartArea _area = mChart.ChartAreas[0];
                _area.AxisX.IsMarginVisible = mConfiguration.Graph.MarginVisibleX;
                _area.AxisY.IsMarginVisible = mConfiguration.Graph.MarginVisibleY;
                _area.Area3DStyle.Enable3D = mConfiguration.Graph.Enable3D;
                _area.Area3DStyle.Inclination = mConfiguration.Graph.Inclination;
                _area.Area3DStyle.Rotation = mConfiguration.Graph.Rotation;
                _area.Area3DStyle.Perspective = mConfiguration.Graph.Perspective;
                _area.Area3DStyle.IsRightAngleAxes = true;
                _area.Area3DStyle.LightStyle = LightStyle.Simplistic;
                _area.AlignmentOrientation = AreaAlignmentOrientations.Vertical;

                WorkBreakdownStructuresViewModel _structures = WorkBreakdownStructuresViewModel.GetInstance();
                ConfigurationViewModel _configuration = ConfigurationViewModel.GetInstance();
                _configuration.Graph.PropertyChanged += this.OnPropertyChanged;
                WorkBreakdownStructureGroupViewModel _objects = null;
                WorkBreakdownStructureGroupViewModel _prefix = null;
                foreach (WorkBreakdownStructureGroupViewModel _group in _structures.Groups)
                {
                    if (_configuration.Object == _group.Name) _objects = _group;
                    else if (null == _prefix) _prefix = _group;
                }

                if (null == _prefix)
                {
                    MessageBox.Show("평가를 하기 위한 충분한 정보가 없습니다.");
                    return;
                }
                foreach (WorkBreakdownStructureViewModel _category in _prefix.WorkBreakdownStructures)
                {
                    if (null == mLegends) mLegends = new List<Legend>();
                    Legend _legend = new Legend(_category.Name);
                    _legend.Title = _category.Name;
                    _legend.Docking = Docking.Right;
                    _legend.IsDockedInsideChartArea = false;
                    mLegends.Add(_legend);
                    if(mConfiguration.Graph.LegendVisible) mChart.Legends.Add(_legend);
                    AppendStructureSequence(_objects.WorkBreakdownStructures, _category.Name);
                }
            }


            Update();
        }

        private void AppendStructureSequence(IEnumerable<WorkBreakdownStructureViewModel> enumerable, string strPrefix)
        {
            foreach (WorkBreakdownStructureViewModel _structure in enumerable)
            {
                string _name = _structure.Name;
                if (!string.IsNullOrEmpty(strPrefix))
                {
                    if (_name.Contains(mSeperator)) throw new ArgumentException("Seperator(" + mSeperator + ") is already exist.");
                    else _name = strPrefix + mSeperator + _name;
                }
                Series _series = new Series(_name);
                mChart.Series.Add(_series);
                _series.ChartType = SeriesChartType.StackedColumn;
                if (0 < _structure.Children.Count) AppendStructureSequence(_structure.Children, strPrefix);
            }
        }

        private WorkBreakdownStructureViewModel GetSequence(ref int nSequence, IEnumerable<WorkBreakdownStructureViewModel> enumerable)
        {
            WorkBreakdownStructureViewModel _found = null;
            int _index = 0;
            while (0 < nSequence)
            {
                WorkBreakdownStructureViewModel _structure = enumerable.ElementAt<WorkBreakdownStructureViewModel>(_index);
                _index++;
                nSequence--;
                if (0 < _structure.Children.Count)
                {
                    WorkBreakdownStructureViewModel _child = GetSequence(ref nSequence, _structure.Children);
                    if (null != _child) _found = _child;
                }
                if (0 == nSequence && null==_found) _found = _structure;
                if (_index == enumerable.Count<WorkBreakdownStructureViewModel>()) break;
            }
            return _found;
        }

        private void Update()
        {
            WorkBreakdownStructureGroupViewModel _reserved = null;
            WorkBreakdownStructuresViewModel _structures = WorkBreakdownStructuresViewModel.GetInstance();
            ConfigurationViewModel _configuration = ConfigurationViewModel.GetInstance();
            foreach (WorkBreakdownStructureGroupViewModel _group in _structures.Groups)
            {
                if (_configuration.Object == _group.Name)
                {
                    _reserved = _group;
                    break;
                }
            }
            if (null != _reserved)
            {
                foreach (RateRowViewModel _row in mViewModel.Rows)
                {
                    for (int i = 0; i < _row.Rates.Count; i++)
                    {
                        ObjectRateViewModel _rate = _row.Rates[i];
                        int _sequence = i + 1;
                        WorkBreakdownStructureViewModel _structure = GetSequence(ref _sequence, _reserved.WorkBreakdownStructures);
                        string _name = _rate.Sequences.First<WorkBreakdownStructureViewModel>().Name + mSeperator + _structure.Name;
                        mChart.Series[_name].Points.AddXY(_rate.Sequences.Last<WorkBreakdownStructureViewModel>().Name, _rate.Rate);
                        mChart.Series[_name]["StackedGroupName"] = _rate.Sequences.First<WorkBreakdownStructureViewModel>().Name;
                    }
                }
                mChart.ResetAutoValues();
                mChart.Invalidate();
            }
        }

        private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            ChartArea _area = mChart.ChartAreas[0];
            switch (e.PropertyName)
            {
                case "MarginVisibleX":
                    _area.AxisX.IsMarginVisible = mConfiguration.Graph.MarginVisibleX;
                    break;
                case "MarginVisibleY":
                    _area.AxisY.IsMarginVisible = mConfiguration.Graph.MarginVisibleY;
                    break;
                case "Enable3D":
                    _area.Area3DStyle.Enable3D = mConfiguration.Graph.Enable3D;
                    break;
                case "Inclination":
                    _area.Area3DStyle.Inclination = mConfiguration.Graph.Inclination;
                    break;
                case "Rotation":
                    _area.Area3DStyle.Rotation = mConfiguration.Graph.Rotation;
                    break;
                case "Perspective":
                    _area.Area3DStyle.Perspective = mConfiguration.Graph.Perspective;
                    break;
                case "LegendVisible":
                    if (mConfiguration.Graph.LegendVisible)
                    {
                        foreach (Legend _legend in mLegends) mChart.Legends.Add(_legend);
                        foreach (Series _series in mChart.Series)
                        {
                            string _prefix = null;
                            string _name = _series.Name;
                            if (_name.Contains(mSeperator))
                            {
                                string[] _names = _name.Split(new string[] { mSeperator }, StringSplitOptions.RemoveEmptyEntries);
                                if (null != _names) if (1 < _names.Length)
                                    {
                                        _prefix = _names[0];
                                        _name = _names[1];
                                    }
                            }
                            if (!string.IsNullOrEmpty(_prefix))
                            {
                                _series.Legend = _prefix;
                                _series.LegendText = _name;
                            }
                        }
                    }
                    else
                    {
                        foreach (Series _series in mChart.Series)
                        {
                            _series.Legend = null;
                            _series.LegendText = null;
                        }
                        mChart.Legends.Clear();
                    }
                    break;
            }
        }
    }
}